home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
pascal
/
err87_13.zip
/
ERROR87.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-01-23
|
12KB
|
406 lines
{$n+,s-}
unit error87;
interface
implementation
uses dos,decode87;
type
controlword = set of (Invalidmask, Denormmask, Zerodivmask, Overflowmask,
Underflowmask, Precisionmask,
CReserved6, IntEnable, Precision0, Precision1, Round0,
Round1, Infinity, CReserved13, CReserved14,
CReserved15);
statusword = set of (Invalid, Denorm, Zerodiv, Overflow, Underflow, Precision,
SReserved6, IntRequest, C0, C1, C2, ST0, ST1, ST2, C3,
Busy);
bitnumbers = 0..15;
state87 = record
control : controlword;
status : statusword;
tags : word;
case boolean of
false: (ip15_0, { Real mode }
ip_opcode,
op15_0,
op19_16 : word;
stack : array[0..7] of Extended);
true: (ip,
op : pointer);
end;
function single_infinite(var s : Single) : Boolean;
begin
if (LongInt(s) and $7FFFFFFF) = $7F800000 then
single_infinite := True
else
single_infinite := False;
end;
function single_nan(var s : Single) : Boolean;
var
words : array[1..2] of Word absolute s;
begin
single_nan := False;
if ((words[2] and $7F80) = $7F80) and (not single_infinite(s)) then
single_nan := True;
end;
function double_infinite(var d : Double) : Boolean;
var
longs : array[1..2] of LongInt absolute d;
begin
if (longs[2] = $7FFFFFFF) and (longs[1] = 0) then
double_infinite := True
else
double_infinite := False;
end;
function double_nan(var d : Double) : Boolean;
var
words : array[1..4] of Word absolute d;
begin
double_nan := False;
if (words[4] and $7FF0) = $7FF0 then { not a number, but maybe INF }
if not double_infinite(d) then
double_nan := True;
end;
function extended_infinite(var e : Extended) : Boolean;
var
words : array[1..5] of Word absolute e;
begin
if ((words[5] and $7FFF) = $7FFF)
and (words[4] = $8000)
and (words[3] = 0)
and (words[2] = 0)
and (words[1] = 0) then
extended_infinite := True
else
extended_infinite := False;
end;
function extended_nan(var e : Extended) : Boolean;
var
words : array[1..5] of Word absolute e;
begin
extended_nan := False;
if ((words[5] and $7FFF) = $7FFF) and
((words[4] and $8000) = $8000) then { not a number, but maybe INF }
if not extended_infinite(e) then
extended_nan := True;
end;
function bcd_zero(var b) : Boolean;
var
words : array[1..5] of Word absolute b;
begin
bcd_zero := False;
if ((words[5] and $7FFF) = 0)
and (words[4] = 0)
and (words[3] = 0)
and (words[2] = 0)
and (words[1] = 0) then
bcd_zero := True;
end;
var
state : state87; { In data segment, in case there isn't much stack
space }
var
oldexitproc : Pointer;
{$f+}
procedure my_exit_proc;
var
opcode : Word;
last_inst : opcode_info;
ops_read : operand_set;
regs_read : operand_set;
op_address, ip_address : Pointer;
tos : 0..7;
op : operand_type;
danger : Boolean;
function physical(reg : operand_type) : Byte;
{ Return the physical register number of a register }
begin
physical := (Ord(reg)+tos) mod 8;
end;
function tag(reg : operand_type) : Byte;
begin
tag := (state.tags shr (2*physical(reg))) and 3;
end;
function is_a_Nan(op : operand_type) : Boolean;
begin
is_a_Nan := False;
case op of
arReg0..arReg7 : begin
if tag(op) <> 2 then
Exit;
is_a_Nan := extended_nan(state.stack[ord(op)]);
end;
arSingle : is_a_Nan := single_nan(Single(op_address^));
arDouble : is_a_Nan := double_nan(Double(op_address^));
arExtended : is_a_Nan := extended_nan(Extended(op_address^));
end;
{ others can't be NaNs }
end;
function is_a_zero(op : operand_type) : Boolean;
begin
is_a_zero := False;
case op of
arReg0..arReg7 : begin
if tag(op) = 1 then
is_a_zero := True;
end;
arSingle :
is_a_zero := (Single(op_address^) = 0.0);
arDouble :
is_a_zero := (Double(op_address^) = 0.0);
arExtended :
is_a_zero := (Extended(op_address^) = 0.0);
arWord :
is_a_zero := (Word(op_address^) = 0);
arLongint :
is_a_zero := (LongInt(op_address^) = 0);
arComp :
is_a_zero := (Comp(op_address^) = 0);
arBCD :
is_a_zero := bcd_zero(op_address^);
end;
end;
function PtrToLong(p:pointer):longint;
begin
PtrToLong := longint(seg(p^)) shl 4 + ofs(p^);
end;
function PtrDiff(p1,p2:pointer):longint;
begin
PtrDiff := abs(PtrToLong(p1)-PtrToLong(p2));
end;
procedure adjust_for_prefix;
var
temp : longint;
begin
temp := PtrToLong(ip_address)-longint(prefixseg)*$10-$100;
{ this is the linear address relative to the start of the program }
ip_address := ptr((temp and $FFFF0000) shl 12, temp and $FFFF);
{ ip_address will have smallest possible segment number }
{ User must manually work out true segment value }
end;
procedure Find_ip;
var
i : integer;
begin
ip_address := Ptr(seg(ErrorAddr^)+PrefixSeg+$10,ofs(ErrorAddr^)-5);
{ Start looking 5 bytes before ErrorAddr }
for i:=1 to 5 do
begin
if byte(ip_address^) = $CD then
exit;
ip_address := Ptr(seg(ip_address^),ofs(ip_address^)+1);
end;
ip_address := nil;
end;
procedure rangecheck(lower,upper:extended);
var
reg : operand_type;
begin
if (last_inst.inst = iFISTP) and (tag(arReg0) = 3) then
reg := arReg7 { This doesn't really belong here, but
a pop happens in trunc() because it temporarily
masks exceptions. }
else
reg := arReg0;
danger := (state.stack[ord(reg)] < lower)
or (state.stack[ord(reg)] > upper);
end;
begin {my_exit_proc}
ExitProc := oldexitproc;
if (ErrorAddr = nil) or (ExitCode <> 207) then
Exit;
inline($cd/$39/$36/state/$9b);
if test8087 > 0 then { Is this a real '87? }
begin
{$ifndef dpmi}
opcode := state.ip_opcode and $07FF+$d800;
op_address := Ptr(state.op19_16 and $F000, state.op15_0);
{$else}
opcode := swap(word(state.ip^));
op_address := state.op;
{$endif}
{$ifdef ver70}
ip_address := ErrorAddr;
{$else}
ip_address := Ptr(state.ip_opcode and $F000, state.ip15_0);
adjust_for_prefix; { Make ip_address on same scale as ErrorAddr }
if ptrdiff(ErrorAddr,ip_address) > 10 then
ErrorAddr := ip_address;
{$endif}
end
else
begin { Handle the emulator }
find_ip;
if ip_address = nil then
begin
writeln('Error probably occurred in library routine. Error87 can''t help.');
exit;
end;
{ Now ip_address points to $CD byte before instruction }
ip_address := Ptr(seg(ip_address^),ofs(ip_address^)+1);
opcode := swap(word(ip_address^)) + $a400;
op_address := Ptr(dseg, Memw[seg(ip_address^):ofs(ip_address^)+2]);
{ we don't know the segment, but we can guess }
end;
decode_opcode(opcode, last_inst);
operands_read(last_inst, ops_read);
regs_read := ops_read*[arReg0..arReg7];
tos := (Word(state.status)